/*
dead63701 version 1.00

started janurary 2008

copyright 2008 Dead_Body
*/

#include "StdAfx.h"
#include "Dead63701.h"

#define F_CARRY		0x01
#define F_OVERFLOW	0x02
#define F_ZERO			0x04
#define F_NEGATIVE	0x08
#define F_IRQ			0x10
#define F_HALFCARRY	0x20

#define A acc.b.A
#define B acc.b.B
#define D acc.D

#define INT_NMI	1
#define INT_IRQ	2
#define INT_TIN	4

#define F_TCSR_ETOI	0x04
#define F_TCSR_EOCI	0x08
#define F_TCSR_EICI	0x10
#define F_TCSR_TOI	0x20
#define F_TCSR_OCI	0x40
#define F_TCSR_ICI	0x80

#define F_TCSR2_EOCI	0x08
#define F_TCSR2_OCI	0x20

static unsigned char c63701Cycles[256] =
{
0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,0,0,0,0,1,1,2,2,4,1,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
1,1,3,3,1,1,4,4,4,5,1,10,5,7,9,12,
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
6,7,7,6,6,7,6,6,6,6,6,5,6,4,3,5,
6,6,6,6,6,6,6,6,6,6,6,4,6,4,3,5,
2,2,2,3,2,2,2,0,2,2,2,2,3,5,3,0,
3,3,3,4,3,3,3,3,3,3,3,3,4,5,4,4,
4,4,4,5,4,4,4,4,4,4,4,4,5,5,5,5,
4,4,4,5,4,4,4,4,4,4,4,4,5,6,5,5,
2,2,2,3,2,2,2,0,2,2,2,2,3,0,3,0,
3,3,3,4,3,3,3,3,3,3,3,3,4,4,4,4,
4,4,4,5,4,4,4,4,4,4,4,4,5,5,5,5,
4,4,4,5,4,4,4,4,4,4,4,4,5,5,5,5
};

static char *OpcodeTable[256] =
{
"??  ","NOP ","??  ","??  ","??  ","??  ","TAP ","TPA ","INX ","DEX ","CLV ","SEV ","CLC ","SEC ","CLI ","SEI ",
"SBA ","CBA ","??  ","??  ","??  ","??  ","TAB ","TBA ","??  ","DAA ","??  ","ABA ","??  ","??  ","??  ","??  ",
"BRA ","BRN ","BHI ","BLS ","BCC ","BLO ","BNE ","BEQ ","BVC ","BVS ","BPL ","BMI ","BGE ","BLT ","BGT ","BLE ",
"TSX ","INS ","PULA","PULB","DES ","TXS ","PSHA","PSHB","??  ","RTS ","??  ","RTI ","??  ","??  ","WAI ","SWI ",
"NEGA","??  ","??  ","COMA","LSRA","??  ","RORA","ASRA","ASLA","ROLA","DECA","??  ","INCA","TSTA","??  ","CLRA",
"NEGB","??  ","??  ","COMB","LSRB","??  ","RORB","ASRB","LSLB","ROLB","DECB","??  ","INCB","TSTB","??  ","CLRB",
"NEG ","OIM ","AIM ","COM ","LSR ","EIM ","ROR ","ASR ","ASL ","ROL ","DEC ","TIM ","INC ","TST ","JMP ","CLR ",
"NEG ","OIM ","AIM ","COM ","LSR ","EIM ","ROR ","ASR ","ASL ","ROL ","DEC ","TIM ","INC ","TST ","JMP ","CLR ",
"SUBA","CMPA","SBCA","SUBD","ANDA","BITA","LDA ","??  ","EORA","ADCA","ORA ","ADDA","CMPX","BSR ","LDS ","STS ",
"SUBA","CMPA","SBCA","SUBD","ANDA","BITA","LDA ","STA ","EORA","ADCA","ORA ","ADDA","CMPX","JSR ","LDS ","STS ",
"SUBA","CMPA","SBCA","SUBD","ANDA","BITA","LDA ","STA ","EORA","ADCA","ORA ","ADDA","CMPX","JSR ","LDS ","STS ",
"SUBA","CMPA","SBCA","SUBD","ANDA","BITA","LDA ","STA ","EORA","ADCA","ORA ","ADDA","CMPX","JSR ","LDS ","STS ",
"SUBB","CMPB","SBCB","ADDD","ANDB","BITB","LDB ","??  ","EORB","ADCB","ORB ","ADDB","LDD ","??  ","LDX ","STX ",
"SUBB","CMPB","SBCB","ADDD","ANDB","BITB","LDB ","STB ","EORB","ADCB","ORB ","ADDB","LDD ","STD ","LDX ","STX ",
"SUBB","CMPB","SBCB","ADDD","ANDB","BITB","LDB ","STB ","EORB","ADCB","ORB ","ADDB","LDD ","STD ","LDX ","STX ",
"SUBB","CMPB","SBCB","ADDD","ANDB","BITB","LDB ","STB ","EORB","ADCB","ORB ","ADDB","LDD ","STD ","LDX ","STX "
};

static FILE *fp;

CDead63701::CDead63701()
{
}

CDead63701::~CDead63701()
{
}

void CDead63701::Reset()
{
CDead6800::Reset();
Port1DDR = 0xFC;				//data sheet refers to this as port 2 ddr
Port2DDR = 0xFE;				//data sheet refers to this as port 3 ddr
TCSR = 0x00;					//timer control status register
Counter = 0x0000;				//free running counter
OutputCompare = 0xFFFF;		//output compare register
InputCapture = 0x0000;		//input capture register
TCSR2 = 0x10;					//timer control status register 2
ModeCtrl = 0x00;				//rate/mode control register
TRCSR = 0x20;					//Tx/Rx control status register
ReceiveData = 0x00;			//receive data register
TransmitData = 0x00;			//transmit data register
RAMCtrlReg = 0x7C;			//ram/port 5 control register
Port6DDR = 0x00;
OutputCompare2 = 0xFFFF;	//output compare register 2
TCSR3 = 0x10;					//timer control status register 3
TimeConstant = 0xFF;			//time constant register
Timer2Up = 0x00;				//timer 2 up counter
//TestRegister = 0xA5;			//test register
TCSRInfo = 0;
Interrupts2 = 0;
}

#include "Dead63701ops.cpp"					//opcodes used in Step()
#include "Dead63701funcs.cpp"					//class members not found here
#include "../dead6800/Dead6800ops.cpp"		//6800 opcodes

void CDead63701::Step()
{
u8 Opcode;										//current opcode
u8 tmp,ntmp,otmp;								//temp variables used by opcodes
u32 tmp2,tmp3;

CHECK_INTERRUPTS;
if(WaitInterrupt)
	{
	AddCycles(1);
	return;
	}
SavePC = PC;
Opcode = OpRead(PC++);
switch(Opcode)
	{
	#include "Dead63701switch.cpp"
	#include "../dead6800/Dead6800switch.cpp"
	}
AddCycles(c63701Cycles[Opcode]);
}

void CDead63701::SaveState(CState *s)
{
CDead6800::SaveState(s);
}

void CDead63701::LoadState(CState *s)
{
CDead6800::LoadState(s);
}

#define ADDR_SHIFT	11
#define ADDR_MASK		0x7FF

u8 CDead63701::OpRead(u32 addr)
{
if(addr < 0x20)			//internal register read
	return(ReadInternalReg(addr));
if(OpPages[addr >> ADDR_SHIFT])
	return(OpPages[addr >> ADDR_SHIFT][addr & ADDR_MASK]);
return(OpPtr(User,addr));
}

u8 CDead63701::Read(u32 addr)
{
if(addr >= 0x10000)
	{
	message("read invalid memory address '$%X', cycle %ld, PC = $%04X\n",addr,Cycle,PC);
	addr &= 0xFFFF;
	}
if(addr < 0x20)			//internal register read
	return(ReadInternalReg(addr));
if(addr < 0x100)			//internal ram read
	{
	//if(RAMCtrlReg & 0x40)
		return(InternalRAM[addr]);
	//else
	//	message("read ram not enabled, addr $%04X\n",addr);
	}
if(ReadPages[addr >> ADDR_SHIFT])
	return(ReadPages[addr >> ADDR_SHIFT][addr & ADDR_MASK]);
return(ReadPtr(User,addr));
}

void CDead63701::Write(u32 addr,u8 data)
{
if(addr >= 0x10000)
	{
	message("write invalid memory address '$%X', cycle %ld, PC = $%04X\n",addr,Cycle,PC);
	addr &= 0xFFFF;
	}
if(addr < 0x20)	//internal register write
	WriteInternalReg(addr,data);
else if(addr < 0x100)
	{
	//if(RAMCtrlReg & 0x40)
		InternalRAM[addr] = data;
	//else
	//	message("write ram not enabled, addr $%04X = $%02X\n",addr,data);
	return;
	}
//allow passthru to user funcs (for ddragon)
/*else*/ if(WritePages[addr >> ADDR_SHIFT])
	WritePages[addr >> ADDR_SHIFT][addr & ADDR_MASK] = data;
else
	WritePtr(User,addr,data);
}

//debugger
enum c63701addrmodes_e
	{
	c63701_addr_none = 0,
	c63701_addr_implied,
	c63701_addr_immediate,
	c63701_addr_immediate8,
	c63701_addr_direct,
	c63701_addr_indexed,
	c63701_addr_extended,
	c63701_addr_relative,
	c63701_addr_relative16
	};

static int GetAddrMode(u8 Opcode)
{
switch(Opcode & 0xF0)
	{
	case 0x00:
	case 0x10:
	case 0x30:
	case 0x40:
	case 0x50:
		return(c63701_addr_implied);
	case 0x20:
		return(c63701_addr_relative);
		return(c63701_addr_implied);
	case 0x60:
		return(c63701_addr_indexed);
	case 0x70:
		return(c63701_addr_extended);
	case 0x80:
		if(Opcode == 0x8D)		//bsr, relative
			return(c63701_addr_relative);
	case 0xC0:
		return(c63701_addr_immediate);
	case 0x90:
	case 0xD0:
		return(c63701_addr_direct);
	case 0xA0:
	case 0xE0:
		return(c63701_addr_indexed);
	case 0xB0:
	case 0xF0:
		return(c63701_addr_extended);
	}
return(c63701_addr_none);
}

u32 CDead63701::Disassemble(char *dest,u32 p)
{
u8 Opcode,N,Reg;
char *Op;
char RegList[] = "XYUS";

Opcode = OpRead(p++);
Op = OpcodeTable[Opcode];
switch(GetAddrMode(Opcode))
	{
	case c63701_addr_none:
	case c63701_addr_implied:
		sprintf(dest,"($%02X)\t%s",Opcode,Op);
		break;
	case c63701_addr_immediate:
		sprintf(dest,"($%02X)\t%s\t$%04X",Opcode,Op,ReadWord(p));
		p += 2;
		break;
	case c63701_addr_immediate8:
		sprintf(dest,"($%02X)\t%s\t$%02X",Opcode,Op,Read(p));
		p += 1;
		break;
	case c63701_addr_direct:
		sprintf(dest,"($%02X)\t%s\t<$%02X ($%04X)",Opcode,Op,Read(p),Read(p));
		p += 1;
		break;
	case c63701_addr_indexed:
		N = Read(p++);
		Reg = RegList[(N >> 5) & 3];
		if((N & 0x80) == 0)
			{
			if((N & 0x10) == 0)
				sprintf(dest,"($%02X)\t%s\t$%X,%c",Opcode,Op,N & 0xF,Reg);
			else
				sprintf(dest,"($%02X)\t%s\t-$%X,%c",Opcode,Op,N & 0xF,Reg);
			}
		else
			{
			char FF[2] = "";
			char FB[2] = "";
			
			if(N & 0x10)
				{
				strcpy(FF,"[");
				strcpy(FB,"]");
				}
			switch(N & 0xF)
				{
				case 0:	sprintf(dest,"($%02X)\t%s\t%s,%c+%s",Opcode,Op,FF,Reg,FB);	break;
				case 1:	sprintf(dest,"($%02X)\t%s\t%s,%c++%s",Opcode,Op,FF,Reg,FB);	break;
				case 2:	sprintf(dest,"($%02X)\t%s\t%s,-%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 3:	sprintf(dest,"($%02X)\t%s\t%s,--%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 4:	sprintf(dest,"($%02X)\t%s\t%s,%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 5:	sprintf(dest,"($%02X)\t%s\t%sB,%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 6:	sprintf(dest,"($%02X)\t%s\t%sA,%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 8:	sprintf(dest,"($%02X)\t%s\t%s<$%02X,%c%s",Opcode,Op,FF,Read(p++),Reg,FB); break;
				case 9:	sprintf(dest,"($%02X)\t%s\t%s>$%04X,%c%s",Opcode,Op,FF,ReadWord(p),Reg,FB); p += 2; break;
				case 11:	sprintf(dest,"($%02X)\t%s\t%sD,%c%s",Opcode,Op,FF,Reg,FB);	break;
				case 12:	sprintf(dest,"($%02X)\t%s\t%s<$%02X,PC%s",Opcode,Op,FF,Read(p++),FB); break;
				case 13:	sprintf(dest,"($%02X)\t%s\t%s>$%04X,PC%s",Opcode,Op,FF,ReadWord(p),FB); p += 2; break;
				case 15:	sprintf(dest,"($%02X)\t%s\t%s$%04X%s",Opcode,Op,FF,ReadWord(p),FB); p += 2; break;
				}
			}
		break;
	case c63701_addr_extended:
		sprintf(dest,"($%02X)\t%s\t[$%02X]",Opcode,Op,ReadWord(p));
		p += 2;
		break;
	case c63701_addr_relative:
		sprintf(dest,"($%02X)\t%s\t$%04X",Opcode,Op,p + (s8)(Read(p) + 1));
		p += 1;
		break;
	case c63701_addr_relative16:
		sprintf(dest,"($%02X)\t%s\t$%04X",Opcode,Op,p + (s16)(ReadWord(p) + 1));
		p += 2;
		break;
	}
return(p);
}

char *CDead63701::GenerateRegNames(char *dest)
{
sprintf(dest,
"pc:\n"
"d:\n"
"x:\n"
"s:\n"
"cc:\n"
"\n"
"vectors\n"
"sci:\n"
"toi:\n"
"oci:\n"
"ici:\n"
"irq:\n"
"swi:\n"
"nmi:\n"
"reset:\n"
);
return(dest);
}

#undef D

char *CDead63701::GenerateRegData(char *dest)
{
sprintf(dest,
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%02X\n"
"\n"
"\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n"
"$%04X\n",
	PC,acc.D,X,S,CC,
	ReadWord(0xFFF0),ReadWord(0xFFF2),ReadWord(0xFFF4),ReadWord(0xFFF6),
	ReadWord(0xFFF8),ReadWord(0xFFFA),ReadWord(0xFFFC),ReadWord(0xFFFE)
);
return(dest);
}
